﻿using System;
using System.Collections.Generic;
using System.Web;
using System.Threading;
using System.IO;


namespace CCPSIP.Message
{
    /// <summary>CCPSIP_014：傳送檔案訊息(Photo,Video,Sticker,Document) API</summary>
    /// idHeader = 裝置 UUID 前八碼。iOS 請使用 [CCPCrypto getIdHeader] 呼叫。
    /// checkcode = 裝置限時驗證碼。iOS 請使用 [CCPCrypto getCheckcode] 呼叫。
    /// ChatID = 聊天ID(對方帳號或ClientGID)。
    /// MsgType = 訊息類型，目前支援 ("P", "V", "I")。
    /// localPID = 發訊方的本機訊息ID。
    /// 上傳檔案1 = Video影片檔。（Video變數名稱="VideoFile"）
    /// 上傳檔案2 = Video縮圖檔。（Video變數名稱="ThumbFile"）
    /// 上傳檔案3 = Audio音訊檔。（Audio變數名稱="AudioFile"）

    public class file_send : IHttpHandler
    {
        private string kFilesRootDir = ChrisKit.RootDir + "CCPSIP\\Files";//ios.ccp.com.tw
        private static Dictionary<string, string> kMsgTypeDirs = new Dictionary<string, string>() {
      { "P", "Photo" }, { "V", "Video" }, { "I", "Sticker" }, { "D", "Document" }, {"A", "Audio"}
    };
        private const string kHashStickerDir = "StickerHash";
        private const string kThumbnailPostfix = "thumb";
        private const string kDateTimeFormat = "yyyy/MM/dd HH:mm:ss";
        private const int kFileSizeLimit = 101;//in MB


        public void ProcessRequest(HttpContext context)
        {
            HttpRequest req = context.Request;
            HttpResponse resp = context.Response;
            resp.ContentType = "text/plain";
            resp.ContentEncoding = System.Text.Encoding.UTF8;
            DateTime reqTime = DateTime.Now;
            string resultStr = "";

            try
            {
                //【01】取得POST參數，驗證身分
                //
                string idHeader = req.Form["idHeader"];
                string checkcode = req.Form["checkcode"];
                string ChatID = req.Form["ChatID"];//聊天ID(對方帳號或ClientGID)
                string MsgType = req.Form["MsgType"];//訊息類型
                int localPID = -1;//發訊方的本機訊息ID

                try
                {
                    ChatID = ChatID.Trim();
                    MsgType = MsgType.Trim();
                    localPID = Convert.ToInt32(req.Form["localPID"]);
                }
                catch
                {
                    throw new Exception("Error_01: Parameter Error");//參數錯誤
                }

                SipUserInfo userInfo = SipKit.GetUserInfo(idHeader, checkcode, req);
                if (userInfo == null)
                {
                    throw new Exception("Error_02: Cannot identify this device");//無法識別此裝置
                }

                if (req.Files.Count < 1)
                {
                    throw new Exception("Error_03: No Upload File");//沒有上傳檔案
                }

                int fileSize = req.Files[0].ContentLength;

                if (fileSize < 3)
                {
                    throw new Exception("Error_04: The file is too small");//檔案太小
                }
                else if (fileSize > kFileSizeLimit * 1048576)
                {
                    throw new Exception("Error_04: The file is too large");//檔案太大
                }
                else if (MsgType == "V")
                {
                    if (req.Files.Count < 2 || req.Files[1].ContentLength < 512)
                        throw new Exception("Error_05: No Thumbnail File");//沒有縮圖檔案
                }


                //【02】由訊息類型選擇副檔名
                //
                string fileTypeName = "";
                string fileTypeExt = "";
                if (MsgType == "P")
                {
                    fileTypeName = "photo";
                    fileTypeExt = ".jpg";
                }
                else if (MsgType == "V")
                {
                    fileTypeName = "video";
                    fileTypeExt = ".mov";
                }
                else if (MsgType == "I")
                {
                    fileTypeName = "sticker";
                    fileTypeExt = ".png";
                }
                else if (MsgType == "D")
                {
                    fileTypeName = "document";
                    fileTypeExt = Path.GetExtension(req.Files[0].FileName).ToLower(); //[0]的寫法不是很好
                }
                else if (MsgType == "A")
                {
                    fileTypeName = "audio";
                    fileTypeExt = ".m4a";
                    //fileTypeExt = Path.GetExtension(req.Files["AudioFile"].FileName).ToLower();
                }
                else
                {
                    throw new Exception("Error_06: Message type not support");//不支援的訊息類型
                }

                string msgPreview = string.Format("{0} sent you a {1}.", userInfo.CustomName, fileTypeName);


                //【03】儲存訊息
                //
                long MsgID = 0;
                bool isToRobot = RobotKit.isRobot(ChatID);
                RobotServiceInfo[] services = null;
                bool isFromRobot = RobotKit.isRobot(userInfo.SIP_Num);
                bool isGroupMsg = SipKit.isGroupID(ChatID);


                //【03-1】傳給Debug機器人的訊息略過
                //
                if (ChatID == "RobotDebug")
                {
                    Dictionary<string, string> debugDict = new Dictionary<string, string>();
                    debugDict["MsgID"] = Convert.ToString(-1);
                    debugDict["MsgTime"] = reqTime.ToString(kDateTimeFormat);
                    debugDict["Filename"] = "FILE_NOT_SAVED";
                    debugDict["LocalPID"] = Convert.ToString(localPID);
                    resp.ContentType = "application/json";
                    fastJSON.JSON.Instance.Parameters.EnableAnonymousTypes = true;
                    resultStr = fastJSON.JSON.Instance.ToJSON(debugDict);
                    return;
                }


                //【03-2】檢查機器人Service權限
                //
                if (isToRobot)
                {
                    string ROBOT_ID = ChatID;
                    services = RobotKit.getServices(userInfo, ROBOT_ID);
                    if (services.Length == 0)
                    {
                        throw new Exception("Error_07: You have no right to use this robot");//無機器人權限
                    }
                }


                if (isGroupMsg)
                {
                    if (!OracleKitGroup.isMemberOfGroup(userInfo.SIP_Num, ChatID))
                    {
                        throw new Exception("Error_08: You are not a member");//你不是群組成員
                    }
                    MsgID = OracleKitMsg.InsertGroupMsgWait(userInfo, ChatID, MsgType, msgPreview, localPID, reqTime);
                }
                else
                {
                    MsgID = OracleKitMsg.InsertMsgOneWait(userInfo.SIP_Num, ChatID, MsgType, msgPreview, localPID, reqTime);
                }


                //【05】組合檔名路徑
                //
                string saveDir = string.Format(@"{0}\{1}\{2:yyyy}\{2:MM}", kFilesRootDir, kMsgTypeDirs[MsgType], reqTime);
                if (!Directory.Exists(saveDir) && MsgType != "I")
                {
                    Directory.CreateDirectory(saveDir);
                }

                string mainFileName = string.Format(@"{0:yyyyMMdd}_{1}_{2}{3}", reqTime, MsgID, userInfo.SIP_Num, fileTypeExt);
                if (isGroupMsg)
                {
                    mainFileName = "G_" + mainFileName;
                }

                string mainFilePath = string.Format(@"{0}\{1}", saveDir, mainFileName);


                //【05-1】貼圖用Hash當作檔名，以節省空間(Start from 2014-04-01)
                //
                if (MsgType == "I")
                {
                    saveDir = string.Format(@"{0}\{1}\{2:yyyy}", kFilesRootDir, kHashStickerDir, reqTime);
                    if (!Directory.Exists(saveDir))
                    {
                        Directory.CreateDirectory(saveDir);
                    }

                    string tempPath = Path.GetTempFileName();
                    req.Files[0].SaveAs(tempPath);
                    string fileMD5 = HashKit.getFileHash(tempPath, HashType.MD5);
                    mainFileName = string.Format("{0:yyyy}_{1}_{2}{3}", reqTime, fileSize, fileMD5, fileTypeExt);
                    mainFilePath = string.Format(@"{0}\{1}", saveDir, mainFileName);

                    if (File.Exists(mainFilePath))
                        File.Delete(tempPath);
                    else
                        File.Move(tempPath, mainFilePath);
                }


                //【06】存檔，修改訊息檔名
                //
                string FileNameMsg = mainFileName;

                if (MsgType == "V")
                {
                    string thumbFileName = string.Format(@"{0:yyyyMMdd}_{1}_{2}_{3}.jpg", reqTime, MsgID, userInfo.SIP_Num, kThumbnailPostfix);
                    if (isGroupMsg)
                    {
                        thumbFileName = "G_" + thumbFileName;
                    }
                    string thumbFilePath = string.Format(@"{0}\{1}", saveDir, thumbFileName);

                    req.Files["VideoFile"].SaveAs(mainFilePath);
                    req.Files["ThumbFile"].SaveAs(thumbFilePath);

                    FileNameMsg = string.Format("{0}; {1}", thumbFileName, mainFileName);
                }
                else
                {
                    if (!File.Exists(mainFilePath))
                    {
                        req.Files[0].SaveAs(mainFilePath);
                    }

                    if (MsgType == "D" || MsgType == "A")
                    {
                        FileNameMsg = string.Format("{0}; {1}\n", mainFileName, req.Files[0].FileName);

                        double fileSizeKB = fileSize / 1024.0;
                        if (fileSizeKB < 1024)
                            FileNameMsg += string.Format("Size: {0:N0} KB", fileSizeKB);
                        else
                            FileNameMsg += string.Format("Size: {0:N1} MB", fileSizeKB / 1024.0);
                    }
                }

                if (isGroupMsg)
                {
                    OracleKitMsg.UpdateGroupMsgFilename(userInfo, MsgID, FileNameMsg);
                }
                else
                {
                    OracleKitMsg.UpdateMsgOneFilename(userInfo.SIP_Num, MsgID, FileNameMsg);
                }


                //【07】通知機器人Service
                //
                if (isToRobot)
                {
                    string ROBOT_ID = ChatID;
                    string Command = "PUSH";
                    RobotServiceInfo rService = services[0];

                    ServiceCallParam sParamObj = new ServiceCallParam(userInfo, rService, Command);
                    new Thread(new ParameterizedThreadStart(CallService)).Start(sParamObj);
                }


                //【08】Log機器人回覆
                //
                if (isFromRobot && (!isGroupMsg))
                {
                    string ROBOT_ID = userInfo.SIP_Num;
                    OracleKitRobot.InsertMsgOneRobot("R", ChatID, ROBOT_ID, ROBOT_ID, MsgID, FileNameMsg, reqTime);
                }


                //【98】通知Push Service
                //
                PushKit.WakePushAsync(PushKit.PushType.Msg);


                //【99】回傳結果
                //
                Dictionary<string, string> resultDict = new Dictionary<string, string>();
                resultDict["MsgID"] = Convert.ToString(MsgID);
                resultDict["MsgTime"] = reqTime.ToString(kDateTimeFormat);
                resultDict["Filename"] = FileNameMsg;
                resultDict["LocalPID"] = Convert.ToString(localPID);

                resp.ContentType = "application/json";
                resp.Charset = null;
                fastJSON.JSON.Instance.Parameters.EnableAnonymousTypes = true;
                resultStr = fastJSON.JSON.Instance.ToJSON(resultDict);
            }
            catch (Exception ex)
            {
                resp.ContentType = "application/xml";
                resultStr = ChrisKit.Ex2Xml(ex, false);
            }
            finally
            {
                int contentLength = resp.ContentEncoding.GetByteCount(resultStr);
                resp.AppendHeader("Content-Length", contentLength.ToString());
                resp.Write(resultStr);
                resp.Flush();
                resp.Close();
            }
        }


        public bool IsReusable
        {
            get
            {
                return false;
            }
        }


        #region 機器人Service呼叫

        /// <summary>
        /// 呼叫機器人Service
        /// </summary>
        /// <param name="param">ServiceCallParam參數物件</param>
        private void CallService(object param)
        {
            if (param is ServiceCallParam)
            {
                ServiceCallParam p = (ServiceCallParam)param;
                RobotKit.CallService(p.UserInfo, p.ServiceInfo, p.Command);
            }
        }


        /// <summary>
        /// 機器人服務呼叫Parameters
        /// </summary>
        private class ServiceCallParam
        {
            private SipUserInfo _UserInfo;
            private RobotServiceInfo _ServiceInfo;
            private string _Command;

            public SipUserInfo UserInfo { get { return this._UserInfo; } }
            public RobotServiceInfo ServiceInfo { get { return this._ServiceInfo; } }
            public string Command { get { return this._Command; } }


            public ServiceCallParam(SipUserInfo userInfo, RobotServiceInfo service, string Command)
            {
                _UserInfo = userInfo;
                _ServiceInfo = service;
                _Command = Command;
            }
        }

        #endregion


    }
}
